﻿using System;
using System.Windows;
using System.Collections.Generic;
using System.Windows.Controls;
using System.Windows.Media;
using Bling.DSL;
using Bling.WPF;
using Bling.Shapes;
using Bling.Animation;
using Bling.Util;

namespace Bling.Tutorial {
  public class BezierScaleTest : Canvas {

    public BezierScaleTest() {
      CanvasBl canvas = this;
      PointBl[] Points = new PointBl[8];
      PointBl[] Original = new PointBl[8];
      PointBl[] Thumbs = new PointBl[8];

      PathShapeBl shape = new PathShapeBl(canvas) {
        Start = { Now = new PointBl(70, 70) },
        Fill = Brushes.LightPink,
        Stroke = { Brush = Brushes.Black, Thickness = 2 },
        OnMouseEnter = (x, y) => {
          foreach (var p in Thumbs) p.Stop(true);
          return true;
        },
      };
      ImageBl image = new ImageBl(canvas) {
        Source = Properties.Resources.Dock,
        LeftTop = new PointBl(75, 75), Size = new PointBl(400, 400),
        IsHitTestVisible = false, ZIndex = 1,
        Opacity = 0.2,
      };
      image.CurrentValue.Stretch = Stretch.Fill;

      SliderBl slider = new SliderBl(canvas) {
        Width = canvas.Width, RightBottom = canvas.Size,
        Minimum = 0, Maximum = 1, Value = .5,
      };


      //{
      //  var i = 0;
      //  Points[0] = shape.Start;
      //  for (int j = 0; j < 4; j++) {
      //    int sign = (j < 2) ? +1 : -1;
      //    OrientationBl orient = (j % 2 == 0) ? Orientation.Horizontal : Orientation.Vertical;
      //    if (i == 0 || i == 5) {

      //      var thumbA = Thumbs[i + 1] = new ThumbBl(canvas) {
      //        ZIndex = 3, Background = Brushes.Red, CanDrag = true,
      //        CenterPosition = { Now = Points[i] + PointBl.Make(orient, 200 * sign) },
      //      };
      //      var thumbB = Thumbs[(i + 2) % Thumbs.Length] = new ThumbBl(canvas) {
      //        ZIndex = 3, Background = Brushes.Blue, CanDrag = true,
      //        CenterPosition = { Now = Points[i] + PointBl.Make(orient, 400 * sign) },
      //      };
      //      // loop around.
      //      QuadraticBezierSegmentBl segment = new QuadraticBezierSegmentBl() {
      //        Point2 = thumbB,
      //      };
      //      // assign the array.
      //      Points[(i + 1)] = segment.Point1;
      //      if (i + 2 == Points.Length) shape.Start = thumbB;
      //      else Points[(i + 2)] = segment.Point2;

      //      var ratio = (thumbA - Points[i]).Select[orient] / ((segment.Point2 - thumbA).Select[orient] + (thumbA - Points[i]).Select[orient]);

      //      PointBl.Bezier(ratio, 1, Points[i], segment.Point1, segment.Point2).Bind = thumbA;
      //      shape.Add(segment);

      //      i += 2;
      //    } else {

      //      var thumbA = Thumbs[i + 1] = new ThumbBl(canvas) {
      //        ZIndex = 3, Background = Brushes.Red, CanDrag = true,
      //        CenterPosition = { Now = Points[i] + PointBl.Make(orient, 133 * sign) },
      //      };
      //      var thumbB = Thumbs[(i + 2) % Thumbs.Length] = new ThumbBl(canvas) {
      //        ZIndex = 3, Background = Brushes.Blue, CanDrag = true,
      //        CenterPosition = { Now = Points[i] + PointBl.Make(orient, 267 * sign) },
      //      };
      //      var thumbC = Thumbs[(i + 3) % Thumbs.Length] = new ThumbBl(canvas) {
      //        ZIndex = 3, Background = Brushes.Green, CanDrag = true,
      //        CenterPosition = { Now = Points[i] + PointBl.Make(orient, 400 * sign) },
      //      };
      //      // loop around.
      //      BezierSegmentBl segment = new BezierSegmentBl() {
      //        Point2 = thumbB,
      //        Point3 = thumbC,
      //      };
      //      // assign the array.
      //      Points[(i + 1)] = segment.Point1;
      //      Points[(i + 2)] = segment.Point2;
      //      if (i + 3 == Points.Length) shape.Start = thumbC;
      //      else Points[(i + 3)] = segment.Point3;

      //      var ratio = (thumbA - Points[i]).Select[orient] / ((segment.Point2 - thumbA).Select[orient] + (thumbA - Points[i]).Select[orient]);

      //      PointBl.Bezier(ratio, 1, Points[i], segment.Point1, segment.Point2, segment.Point3).Bind = thumbA;

      //      shape.Add(segment); 
            
      //      i += 3;
      //    }

      //  }
      //    (i == Points.Length).Assert();
      //}

      {
        var i = 0;
        Points[0] = shape.Start;
        for (int j = 0; j < 4; j++) {
          int sign = (j < 2) ? +1 : -1;
          OrientationBl orient = (j % 2 == 0) ? Orientation.Horizontal : Orientation.Vertical;

          var thumbA = Thumbs[i + 1] = new ThumbBl(canvas) {
            ZIndex = 3, Background = Brushes.Red, CanDrag = true,
            CenterPosition = { Now = Points[i] + PointBl.Make(orient, 200 * sign) },
          };
          var thumbB = Thumbs[(i + 2) % Thumbs.Length] = new ThumbBl(canvas) {
            ZIndex = 3, Background = Brushes.Blue, CanDrag = true,
            CenterPosition = { Now = Points[i] + PointBl.Make(orient, 400 * sign) },
          };
          // loop around.
          QuadraticBezierSegmentBl segment = new QuadraticBezierSegmentBl() {
            Point2 = thumbB,
          };
          // assign the array.
          Points[i + 1] = segment.Point1;
          if (i + 2 == Points.Length) shape.Start = thumbB;
          else Points[i + 2] = segment.Point2;

          var ratio = (thumbA - Points[i]).Select[orient] / ((segment.Point2 - thumbA).Select[orient] + (thumbA - Points[i]).Select[orient]);

          PointBl.Bezier(ratio, 1, Points[i], segment.Point1, segment.Point2).Bind = thumbA;
          shape.Segments.Add(segment);

          i += 2;
        }
        (i == Points.Length).Assert();
      }

      for (int i = 0; i < Points.Length; i++) {
        Original[i] = Thumbs[i].CurrentValue;
      }
      var button1 = new ButtonBl(canvas) {
        RightBottom = slider.RightTop, Content = "ToSquare",
        Click = () => {
          for (int i = 0; i < Points.Length; i++)
            Thumbs[i].Animate.AutoReverse().Forever().Tween(t => t.Ease.Bounce.Out).To = Original[i];
        }
      };

      var Disappear = new SliderBl(canvas) {
        Visibility = false, Minimum = 0, Maximum = 1, Value = 0,
      };

      var button2 = new ButtonBl(canvas) {
        RightBottom = button1.LeftBottom, Content = "Disappear",
        Click = () => {
 
 //         Thumbs[0].Animate.AutoReverse().To = Original[4];
 //         Thumbs[2].Animate.AutoReverse().To = Original[4];
          Thumbs[6].Animate.To = Original[4] - new PointBl(9, 0);
          Thumbs[5].Animate.To = Original[4] - new PointBl(7, 0);
          Thumbs[4].Animate.To = Original[4] - new PointBl(5, 0);
          Thumbs[7].Animate.To = Original[7] + new PointBl(100, 0);//0.5.Bl().Lerp(Thumbs[0], Thumbs[6]) + new PointBl(50, 0);
          Thumbs[1].Animate.To = Original[1] + new PointBl(0, 50);//0.5.Bl().Lerp(Thumbs[0], Thumbs[2]) + new PointBl(0, 50);
          Thumbs[3].Animate.StopOnCompleted(false).Completed((p) => {
            for (int i = 0; i < Points.Length; i++) {
              Thumbs[i].Stop(true);
              Thumbs[i].Animate.Tween(t => t.Ease.Bounce.Out).To = Original[4] - new PointBl(5, 0);
            }
          }).To = Original[3] - new PointBl(50, 0);//0.5.Bl().Lerp(Thumbs[2], Thumbs[4]) - new PointBl(50, 0);

        }
      };

      var button3 = new ButtonBl(canvas) {
        RightBottom = button2.LeftBottom, Content = "Appear",
        Click = () => {
 
          Thumbs[0].Animate.To = Original[0];
          Thumbs[2].Animate.To = Original[2];
          Thumbs[6].Animate.To = Original[4] - new PointBl(9, 0);
          Thumbs[5].Animate.To = Original[4] - new PointBl(7, 0);
          Thumbs[4].Animate.To = Original[4] - new PointBl(5, 0);
          Thumbs[7].Animate.To = Original[7] + new PointBl(100, 0);//0.5.Bl().Lerp(Thumbs[0], Thumbs[6]) + new PointBl(50, 0);
          Thumbs[1].Animate.To = Original[1] + new PointBl(0, 50);//0.5.Bl().Lerp(Thumbs[0], Thumbs[2]) + new PointBl(0, 50);
          Thumbs[3].Animate.StopOnCompleted(false).Completed((p) => {
            for (int i = 0; i < Points.Length; i++) {
              Thumbs[i].Stop(true);
              Thumbs[i].Animate.Tween(t => t.Ease.Bounce.Out).To = Original[i] - new PointBl(30, 40);
            }
          }).To = Original[3] - new PointBl(50, 0);//0.5.Bl().Lerp(Thumbs[2], Thumbs[4]) - new PointBl(50, 0);

        }
      };  
    
      DoubleBl minX = Points[0].X;
      DoubleBl minY = Points[0].Y;

      DoubleBl maxX = Points[0].X;
      DoubleBl maxY = Points[0].Y;

      for (int i = 2; i < Points.Length - 1; i += 2) {
        // look at 0, 1, 2
        var q = PointBl.Bezier(.5, Points[i - 2], Points[i - 1], Points[i - 0]);

        minX = minX.Min(Points[i].X).Min(q.X);
        minY = minY.Min(Points[i].Y).Min(q.Y);
        maxX = maxX.Max(Points[i].X).Max(q.X);
        maxY = maxY.Max(Points[i].Y).Max(q.Y);
      }
      {
        var q = PointBl.Bezier(.5, Points[6], Points[7], Points[0]);
        minX = minX.Min(q.X);
        minY = minY.Min(q.Y);
        maxX = maxX.Max(q.X);
        maxY = maxY.Max(q.Y);
      }

      DoubleBl deltaX = maxX - minX;
      DoubleBl deltaY = maxY - minY;

      Func<PointBl, PointBl> Relative = (p) =>
        //        (p - shape.LeftTop) / shape.Size;
        (p - new PointBl(minX, minY)) / new PointBl(deltaX, deltaY);

      ImageBrushBl brush = new ImageBrushBl() { ImageSource = Properties.Resources.Dock };
      shape.Effect.Custom = (input, uv) => {
        var p0 = Relative(Points[0]);
        var p2 = Relative(Points[2]);
        var p4 = Relative(Points[4]);
        var p6 = Relative(Points[6]);

        //return ColorBl.FromScRGB(input[uv].ScA, brush[uv].ScRGB * input[uv].ScA);
        //uv = uv.Distort(p0, p2, p4, p6);

        var right = PointBl.Bezier(uv.Y, p2, Relative(Points[3]), p4);
        var left = PointBl.Bezier(1.0 - uv.Y, p6, Relative(Points[7]), p0);

        var top = PointBl.Bezier(uv.X, p0, Relative(Points[1]), p2);
        var bot = PointBl.Bezier(1 - uv.X, p4, Relative(Points[5]), p6);

        var newX = (uv - left).Length / ((uv - right).Length + (uv - left).Length);
        var newY = (uv - top).Length / ((bot - uv).Length + (uv - top).Length);
        return ColorBl.FromScRGB(input[uv].ScA, brush[new PointBl(newX, newY)].ScRGB * input[uv].ScA);
      };
      //1:
      //var right = PointBl.Bezier(uv.Y, p2, Relative(Points[3]), p4);
      //var left = PointBl.Bezier(1.0 - uv.Y, p6, Relative(Points[7]), p0);

      //var top = PointBl.Bezier(uv.X, p0, Relative(Points[1]), p2);
      //var bot = PointBl.Bezier(1 - uv.X, p4, Relative(Points[5]), p6);

      //var newX = (uv.X - left.X) / (right.X - left.X);
      //var newY = (uv.Y - top.Y) / (bot.Y - top.Y);
      //return ColorBl.FromScRgb(input[uv].ScA, brush[new PointBl(newX, newY)].ScRGB * input[uv].ScA);

      //2:
      //var right = PointBl.Bezier(uv.Y, p2, Relative(Points[3]), p4);
      //var left = PointBl.Bezier(1.0 - uv.Y, p6, Relative(Points[7]), p0);
      //var mid = PointBl.Bezier(uv.Y, Relative(Points[1]), Relative(Points[8]), Relative(Points[5]));

      //var newXY = PointBl.Bezier(1.0 - uv.X, right, mid, left);       
      //return ColorBl.FromScRgb(input[uv].ScA, brush[newXY].ScRGB * input[uv].ScA);

    }
  }

}
